package mahjong;


import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Random;

import org.junit.*;

import static org.junit.Assert.*;

public class Milestone1Test
{
	private Board testBoard;
	private Tile[] testTiles;
	private Viewer testViewer;
	private Player testPlayer;
	private HighScoreList hsl;
	
	@Before
	public void setUp()
	{
		String boardName = "Layouts"+ java.io.File.separator + "test.layout";
		testBoard =  new Board(boardName);
		testTiles = testBoard.getContent();
		testPlayer = new Player();
		testViewer = new Viewer(testBoard, testPlayer ); 
		testPlayer.setBoard(testBoard);
		testPlayer.setView(testViewer);
		hsl = new HighScoreList("jUnitTest");
	}

	@Test
	public void tilesSetAndGet()
	{
		Tile t = new Tile(7, 2);

		assertTrue(t.getValue() == 7);
		assertTrue(t.getSubindex() == 2);
	}
	
	/*
	 * This test clicks a tile twice
	 * checking for selection on the first click
	 * and deselection on the second
	 */
	@Test
	public void testSelectDeselectTile()
	{
		
		testBoard.makeMove(testTiles[0]);
		assertTrue(testTiles[0].isSelected());
		assertFalse(testTiles[1].isSelected());
		assertFalse(testTiles[2].isSelected());
		assertFalse(testTiles[3].isSelected());
		testBoard.makeMove(testTiles[0]);
		assertFalse(testTiles[0].isSelected());
		assertFalse(testTiles[1].isSelected());
		assertFalse(testTiles[2].isSelected());
		assertFalse(testTiles[3].isSelected());
	}
	
	/*
	 * This test clicks a first tile and then
	 * a second not matching tile
	 * checking for selection of the second
	 * and deselection of the first
	 */
	@Test
	public void testSelectDiffTile()
	{
		testBoard.makeMove(testTiles[0]);
		testBoard.makeMove(testTiles[3]);
		assertFalse(testTiles[0].isSelected());
		assertFalse(testTiles[1].isSelected());
		assertFalse(testTiles[2].isSelected());
		assertTrue(testTiles[3].isSelected());
		testBoard.makeMove(testTiles[3]);
	}
	
	/*
	 * This test clicks a first tile and then
	 * a second matching tile
	 * checking for removal of both
	 */
	@Test
	public void testSelectRemoveTile()
	{		
		testBoard.makeMove(testTiles[2]);
		testBoard.makeMove(testTiles[3]);
		assertFalse(testTiles[0].isSelected());
		assertFalse(testTiles[1].isSelected());
		assertFalse(testTiles[2].isSelected());
		assertFalse(testTiles[3].isSelected());
		assertFalse(testTiles[0].isRemoved());
		assertFalse(testTiles[1].isRemoved());
		assertTrue(testTiles[2].isRemoved());
		assertTrue(testTiles[3].isRemoved());
	}
	
	
	/*
	 * Test empty board
	 */
	@Test
	public void testEmptyState()
	{
		for(int i = 0; i < testTiles.length; i ++){
			testTiles[i].removeFromPlay();
		}
		assertTrue(testBoard.isEmpty());
		for(int i = 0; i < testTiles.length; i ++){
			testTiles[i].addToPlay();
		}
	}
	/*
	 * Test deadlock state
	 */
	@Test
	public void testDeadlockState()
	{
		testTiles[0].removeFromPlay();
		testTiles[2].removeFromPlay();
		assertTrue(testBoard.isDeadLock());
		for(int i = 0; i < testTiles.length; i ++){
			testTiles[i].addToPlay();
		}
	}
	
	/*
	 * Remove tiles and reset to check
	 * if all tiles are in play after reset
	 */
	@Test
	public void testNewGame()
	{
		testTiles[0].removeFromPlay();
		testTiles[2].removeFromPlay();
		testBoard.reset();
		for(int i = 0; i < testTiles.length; i ++){
			assertTrue(!testTiles[i].isRemoved());
		}
	}

	@Test
	public void tileSetAndGet()
	{
		Tile t = new Tile();
		Random r = new Random();

		int x = r.nextInt();
		int y = r.nextInt();
		int z = r.nextInt();
		t.setCoord(z, y, x);
		assertTrue(t.getX() == x);
		assertTrue(t.getY() == y);
		assertTrue(t.getZ() == z);

		int i = r.nextInt();
		t.setId(i);
		assertTrue(t.getId() == i);

		int v = r.nextInt();
		int s = r.nextInt();
		t.setValue(v);
		t.setSubindex(s);
		assertTrue(t.getValue() == v);
		assertTrue(t.getSubindex() == s);
	}

	@Test
	public void tileLogic()
	{
		Tile t = new Tile();
		Tile ul = new Tile();
		Tile ur = new Tile();
		Tile lr = new Tile();
		Tile ll = new Tile();
		Tile tul = new Tile();
		Tile tur = new Tile();
		Tile tlr = new Tile();
		Tile tll = new Tile();

		assertTrue(t.canRemove());

		// put something on top
		t.setAdjacentTile(Tile.TUL, tul);
		assertFalse(t.canRemove());
		// remove it
		t.getAdjacentTile(Tile.TUL).removeFromPlay();
		assertTrue(t.canRemove());
		// put something on top
		t.setAdjacentTile(Tile.TUR, tur);
		assertFalse(t.canRemove());
		// remove it
		t.getAdjacentTile(Tile.TUR).removeFromPlay();
		assertTrue(t.canRemove());
		// put something on top
		t.setAdjacentTile(Tile.TLR, tlr);
		assertFalse(t.canRemove());
		// remove it
		t.getAdjacentTile(Tile.TLR).removeFromPlay();
		assertTrue(t.canRemove());
		// put something on top
		t.setAdjacentTile(Tile.TLL, tll);
		System.out.println(t.canRemove());
		assertFalse(t.canRemove());
		// remove it
		t.getAdjacentTile(Tile.TLL).removeFromPlay();
		assertTrue(t.canRemove());

		// put tiles on both sides
		t.setAdjacentTile(Tile.UL, ul);
		assertTrue(t.canRemove());

		t.setAdjacentTile(Tile.UR, ur);
		assertFalse(t.canRemove());

		t.setAdjacentTile(Tile.LR, lr);
		assertFalse(t.canRemove());

		t.setAdjacentTile(Tile.LL, ll);
		assertFalse(t.canRemove());

		// only remove the tiles on the left
		ul.removeFromPlay();
		ll.removeFromPlay();
		assertTrue(t.canRemove());

		// only remove the tiles on the right
		ul.addToPlay();
		ll.addToPlay();
		ur.removeFromPlay();
		lr.removeFromPlay();
		assertTrue(t.canRemove());

		// put something back on top
		t.getAdjacentTile(Tile.TUL).addToPlay();
		assertFalse(t.canRemove());
		// remove it
		t.getAdjacentTile(Tile.TUL).removeFromPlay();
		assertTrue(t.canRemove());
		// put something on top
		t.getAdjacentTile(Tile.TUR).addToPlay();
		assertFalse(t.canRemove());
		// remove it
		t.getAdjacentTile(Tile.TUR).removeFromPlay();
		assertTrue(t.canRemove());
		// put something on top
		t.getAdjacentTile(Tile.TLR).addToPlay();
		assertFalse(t.canRemove());
		// remove it
		t.getAdjacentTile(Tile.TLR).removeFromPlay();
		assertTrue(t.canRemove());
		// put something on top
		t.getAdjacentTile(Tile.TLL).addToPlay();
		assertFalse(t.canRemove());
		// remove it
		t.getAdjacentTile(Tile.TLL).removeFromPlay();
		assertTrue(t.canRemove());

		// put back tiles on both sides
		t.getAdjacentTile(Tile.UL).addToPlay();
		assertTrue(t.canRemove());

		t.getAdjacentTile(Tile.UR).addToPlay();
		assertFalse(t.canRemove());

		t.getAdjacentTile(Tile.LR).addToPlay();
		assertFalse(t.canRemove());

		t.getAdjacentTile(Tile.LL).addToPlay();
		assertFalse(t.canRemove());

		// only remove the tiles on the left
		ul.removeFromPlay();
		ll.removeFromPlay();
		assertTrue(t.canRemove());

		// only remove the tiles on the right
		ul.addToPlay();
		ll.addToPlay();
		ur.removeFromPlay();
		lr.removeFromPlay();
		assertTrue(t.canRemove());
	}
	
}
